home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / DirectX SDK / DXSDK / samples / Multimedia / DirectShow_WinXP / VMR / VMRXcl / d3dfont.cpp < prev    next >
C/C++ Source or Header  |  2001-10-08  |  14KB  |  412 lines

  1. //-----------------------------------------------------------------------------
  2. // File: D3DFont.cpp
  3. //
  4. // Desc: Texture-based font class
  5. //
  6. // Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #include <streams.h>
  9. #include <stdio.h>
  10. #include <tchar.h>
  11.  
  12. #include <ddraw.h>
  13. #define D3D_OVERLOADS
  14. #include <d3d.h>
  15. #include "D3DFont.h"
  16.  
  17.  
  18. #define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
  19.  
  20. inline FONT2DVERTEX InitFont2DVertex( const D3DXVECTOR4& p, D3DCOLOR color,
  21.                                       FLOAT tu, FLOAT tv )
  22. {
  23.     FONT2DVERTEX v;
  24.  
  25.     v.p.x = p.x;
  26.     v.p.y = p.y;
  27.     v.p.z = p.z;
  28.     v.p.w = p.w;
  29.     v.color = color;
  30.     v.tu = tu;
  31.     v.tv = tv;
  32.  
  33.     return v;
  34. }
  35.  
  36. //-----------------------------------------------------------------------------
  37. // Name: CD3DFont()
  38. // Desc: Font class constructor
  39. //-----------------------------------------------------------------------------
  40. CD3DFont::CD3DFont( TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags )
  41. {
  42.     _tcscpy( m_strFontName, strFontName );
  43.     m_dwFontHeight         = dwHeight;
  44.     m_dwFontFlags          = dwFlags;
  45.  
  46.     m_pd3dDevice           = NULL;
  47.     m_pTexture             = NULL;
  48.     ZeroMemory(&m_VB, sizeof(m_VB));
  49.  
  50.     m_dwSavedStateBlock    = 0L;
  51.     m_dwDrawTextStateBlock = 0L;
  52. }
  53.  
  54. //-----------------------------------------------------------------------------
  55. // Name: ~CD3DFont()
  56. // Desc: Font class destructor
  57. //-----------------------------------------------------------------------------
  58. CD3DFont::~CD3DFont()
  59. {
  60.     InvalidateDeviceObjects();
  61.     DeleteDeviceObjects();
  62. }
  63.  
  64. //-----------------------------------------------------------------------------
  65. // Name: InitDeviceObjects()
  66. // Desc: Initializes device-dependent objects, including the vertex buffer used
  67. //       for rendering text and the texture map which stores the font image.
  68. //-----------------------------------------------------------------------------
  69. HRESULT CD3DFont::InitDeviceObjects(
  70.     LPDIRECTDRAW7 pDD,
  71.     LPDIRECT3DDEVICE7 pd3dDevice
  72.     )
  73. {
  74.     HRESULT hr;
  75.  
  76.     // Keep a local copy of the device
  77.     m_pd3dDevice = pd3dDevice;
  78.  
  79.     // Establish the font and texture size
  80.     m_fTextScale  = 1.0f; // Draw fonts into texture without scaling
  81.  
  82.     // Large fonts need larger textures
  83.     if( m_dwFontHeight > 40 )
  84.         m_dwTexWidth = m_dwTexHeight = 1024;
  85.     else if( m_dwFontHeight > 20 )
  86.         m_dwTexWidth = m_dwTexHeight = 512;
  87.     else
  88.         m_dwTexWidth  = m_dwTexHeight = 256;
  89.  
  90.     // If requested texture is too big, use a smaller texture and smaller font,
  91.     // and scale up when rendering.
  92.     D3DDEVICEDESC7 d3dCaps;
  93.     m_pd3dDevice->GetCaps( &d3dCaps );
  94.  
  95.     if( m_dwTexWidth > d3dCaps.dwMaxTextureWidth )
  96.     {
  97.         m_fTextScale = (FLOAT)d3dCaps.dwMaxTextureWidth / (FLOAT)m_dwTexWidth;
  98.         m_dwTexWidth = m_dwTexHeight = d3dCaps.dwMaxTextureWidth;
  99.     }
  100.  
  101.     DDSURFACEDESC2 ddsd;
  102.     INITDDSTRUCT(ddsd);
  103.     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
  104.  
  105.     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
  106.     ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_HINTSTATIC;
  107.  
  108.     ddsd.dwWidth  = m_dwTexWidth;
  109.     ddsd.dwHeight = m_dwTexHeight;
  110.     ddsd.ddpfPixelFormat.dwFourCC = BI_RGB;
  111.     ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
  112.     ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
  113.     ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0xF000;
  114.     ddsd.ddpfPixelFormat.dwRBitMask = 0x0F00;
  115.     ddsd.ddpfPixelFormat.dwGBitMask = 0x00F0;
  116.     ddsd.ddpfPixelFormat.dwBBitMask = 0x000F;
  117.  
  118.     // Create a new texture for the font
  119.     hr = pDD->CreateSurface(&ddsd, &m_pTexture, NULL);
  120.  
  121.     if( FAILED(hr) )
  122.         return hr;
  123.  
  124.     // Prepare to create a bitmap
  125.     DWORD*      pBitmapBits;
  126.     BITMAPINFO bmi;
  127.     ZeroMemory( &bmi.bmiHeader,  sizeof(BITMAPINFOHEADER) );
  128.     bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
  129.     bmi.bmiHeader.biWidth       =  (int)m_dwTexWidth;
  130.     bmi.bmiHeader.biHeight      = -(int)m_dwTexHeight;
  131.     bmi.bmiHeader.biPlanes      = 1;
  132.     bmi.bmiHeader.biCompression = BI_RGB;
  133.     bmi.bmiHeader.biBitCount    = 32;
  134.  
  135.     // Create a DC and a bitmap for the font
  136.     HDC     hDC       = CreateCompatibleDC( NULL );
  137.     HBITMAP hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
  138.                                           (VOID**)&pBitmapBits, NULL, 0 );
  139.     SetMapMode( hDC, MM_TEXT );
  140.  
  141.     // Create a font.  By specifying ANTIALIASED_QUALITY, we might get an
  142.     // antialiased font, but this is not guaranteed.
  143.     INT nHeight    = -MulDiv( m_dwFontHeight,
  144.         (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72 );
  145.     DWORD dwBold   = (m_dwFontFlags&D3DFONT_BOLD)   ? FW_BOLD : FW_NORMAL;
  146.     DWORD dwItalic = (m_dwFontFlags&D3DFONT_ITALIC) ? TRUE    : FALSE;
  147.     HFONT hFont    = CreateFont( nHeight, 0, 0, 0, dwBold, dwItalic,
  148.                           FALSE, FALSE, DEFAULT_CHARSET, OUT_STRING_PRECIS,
  149.                           CLIP_STROKE_PRECIS, ANTIALIASED_QUALITY,
  150.                           VARIABLE_PITCH, m_strFontName );
  151.     if( NULL==hFont )
  152.         return E_FAIL;
  153.  
  154.     SelectObject( hDC, hbmBitmap );
  155.     SelectObject( hDC, hFont );
  156.  
  157.     // Set text properties
  158.     SetTextColor( hDC, RGB(255,255,255) );
  159.     SetBkColor(   hDC, 0x00000000 );
  160.     SetTextAlign( hDC, TA_TOP );
  161.  
  162.     // Loop through all printable character and output them to the bitmap..
  163.     // Meanwhile, keep track of the corresponding tex coords for each character.
  164.     DWORD x = 0;
  165.     DWORD y = 0;
  166.     TCHAR str[2] = _T("x");
  167.     SIZE size;
  168.  
  169.     for( TCHAR c=32; c<127; c++ )
  170.     {
  171.         str[0] = c;
  172.         GetTextExtentPoint32( hDC, str, 1, &size );
  173.  
  174.         if( (DWORD)(x+size.cx+1) > m_dwTexWidth )
  175.         {
  176.             x  = 0;
  177.             y += size.cy+1;
  178.         }
  179.  
  180.         ExtTextOut( hDC, x+0, y+0, ETO_OPAQUE, NULL, str, 1, NULL );
  181.  
  182.         m_fTexCoords[c-32][0] = ((FLOAT)(x+0))/m_dwTexWidth;
  183.         m_fTexCoords[c-32][1] = ((FLOAT)(y+0))/m_dwTexHeight;
  184.         m_fTexCoords[c-32][2] = ((FLOAT)(x+0+size.cx))/m_dwTexWidth;
  185.         m_fTexCoords[c-32][3] = ((FLOAT)(y+0+size.cy))/m_dwTexHeight;
  186.  
  187.         x += size.cx+1;
  188.     }
  189.  
  190.     // Lock the surface and write the alpha values for the set pixels
  191.     m_pTexture->Lock(NULL, &ddsd, DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL);
  192.  
  193.     WORD* pDst16 = (WORD*)ddsd.lpSurface;
  194.     BYTE bAlpha; // 4-bit measure of pixel intensity
  195.  
  196.     for( y=0; y < m_dwTexHeight; y++ )
  197.     {
  198.         for( x=0; x < m_dwTexWidth; x++ )
  199.         {
  200.             bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth*y + x] & 0xff) >> 4);
  201.             if (bAlpha > 0)
  202.             {
  203.                 *pDst16++ = (WORD) ((bAlpha << 12) | 0x0fff);
  204.             }
  205.             else
  206.             {
  207.                 *pDst16++ = 0x0000;
  208.             }
  209.         }
  210.     }
  211.  
  212.     // Done updating texture, so clean up used objects
  213.     m_pTexture->Unlock(NULL);
  214.     DeleteObject( hbmBitmap );
  215.     DeleteDC( hDC );
  216.     DeleteObject( hFont );
  217.  
  218.     return S_OK;
  219. }
  220.  
  221. //-----------------------------------------------------------------------------
  222. // Name: RestoreDeviceObjects()
  223. // Desc:
  224. //-----------------------------------------------------------------------------
  225. HRESULT CD3DFont::RestoreDeviceObjects()
  226. {
  227.     // Create vertex buffer for the letters
  228.  
  229.     ZeroMemory(&m_VB, sizeof(m_VB));
  230.  
  231.     // Create the state blocks for rendering text
  232.     m_pd3dDevice->SetTexture(0, m_pTexture);
  233.  
  234.     m_pd3dDevice->SetRenderState(D3DRENDERSTATE_BLENDENABLE, TRUE);
  235.     m_pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
  236.     m_pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
  237.  
  238.     m_pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, TRUE);
  239.     m_pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHAREF, 0x08);
  240.     m_pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHAFUNC,  D3DCMP_GREATEREQUAL);
  241.  
  242.     m_pd3dDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
  243.     m_pd3dDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE);
  244.  
  245.  
  246.     m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  247.     m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  248.     m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  249.     m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
  250.     m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  251.     m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
  252.  
  253.     m_pd3dDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_POINT);
  254.     m_pd3dDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_POINT);
  255.     m_pd3dDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTFP_NONE);
  256.  
  257.     m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0 );
  258.     m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
  259.  
  260.     m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
  261.     m_pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );
  262.  
  263.     return S_OK;
  264. }
  265.  
  266.  
  267. //-----------------------------------------------------------------------------
  268. // Name: InvalidateDeviceObjects()
  269. // Desc: Destroys all device-dependent objects
  270. //-----------------------------------------------------------------------------
  271. HRESULT CD3DFont::InvalidateDeviceObjects()
  272. {
  273.     ZeroMemory(&m_VB, sizeof(m_VB));
  274.  
  275.     // Delete the state blocks
  276.     if( m_pd3dDevice )
  277.     {
  278.         if (m_dwSavedStateBlock)
  279.             m_pd3dDevice->DeleteStateBlock(m_dwSavedStateBlock);
  280.  
  281.         if (m_dwDrawTextStateBlock)
  282.             m_pd3dDevice->DeleteStateBlock(m_dwDrawTextStateBlock);
  283.     }
  284.  
  285.     m_dwSavedStateBlock    = 0L;
  286.     m_dwDrawTextStateBlock = 0L;
  287.  
  288.     return S_OK;
  289. }
  290.  
  291.  
  292. //-----------------------------------------------------------------------------
  293. // Name: DeleteDeviceObjects()
  294. // Desc: Destroys all device-dependent objects
  295. //-----------------------------------------------------------------------------
  296. HRESULT CD3DFont::DeleteDeviceObjects()
  297. {
  298.     RELEASE(m_pTexture);
  299.     m_pd3dDevice = NULL;
  300.  
  301.     return S_OK;
  302. }
  303.  
  304.  
  305. //-----------------------------------------------------------------------------
  306. // Name: GetTextExtent()
  307. // Desc: Get the dimensions of a text string
  308. //-----------------------------------------------------------------------------
  309. HRESULT CD3DFont::GetTextExtent( TCHAR* strText, SIZE* pSize )
  310. {
  311.     if( NULL==strText || NULL==pSize )
  312.         return E_FAIL;
  313.  
  314.     FLOAT fRowWidth  = 0.0f;
  315.     FLOAT fRowHeight = (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
  316.     FLOAT fWidth     = 0.0f;
  317.     FLOAT fHeight    = fRowHeight;
  318.  
  319.     while( *strText )
  320.     {
  321.         TCHAR c = *strText++;
  322.  
  323.         if( c == _T('\n') )
  324.         {
  325.             fRowWidth = 0.0f;
  326.             fHeight  += fRowHeight;
  327.         }
  328.         if( c < _T(' ') )
  329.             continue;
  330.  
  331.         FLOAT tx1 = m_fTexCoords[c-32][0];
  332.         FLOAT tx2 = m_fTexCoords[c-32][2];
  333.  
  334.         fRowWidth += (tx2-tx1)*m_dwTexWidth;
  335.  
  336.         if( fRowWidth > fWidth )
  337.             fWidth = fRowWidth;
  338.     }
  339.  
  340.     pSize->cx = (int)fWidth;
  341.     pSize->cy = (int)fHeight;
  342.  
  343.     return S_OK;
  344. }
  345.  
  346.  
  347. //-----------------------------------------------------------------------------
  348. // Name: DrawText()
  349. // Desc: Draws 2D text
  350. //-----------------------------------------------------------------------------
  351. HRESULT CD3DFont::DrawText( FLOAT sx, FLOAT sy, DWORD dwColor,
  352.                             TCHAR* strText, DWORD dwFlags )
  353. {
  354.     if( m_pd3dDevice == NULL )
  355.         return E_FAIL;
  356.  
  357.     // Setup renderstate
  358.     RestoreDeviceObjects();
  359.  
  360.     // Set filter states
  361.     if( dwFlags & D3DFONT_FILTERED )
  362.     {
  363.         m_pd3dDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_LINEAR);
  364.         m_pd3dDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR);
  365.     }
  366.  
  367.     FLOAT fStartX = sx;
  368.  
  369.     // Fill vertex buffer
  370.     FONT2DVERTEX* pVertices = NULL;
  371.     DWORD         dwNumTriangles = 0;
  372.     pVertices = &m_VB[0];
  373.  
  374.     while( *strText )
  375.     {
  376.         TCHAR c = *strText++;
  377.  
  378.         if( c == _T('\n') )
  379.         {
  380.             sx = fStartX;
  381.             sy += (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
  382.         }
  383.         if( c < _T(' ') )
  384.             continue;
  385.  
  386.         FLOAT tx1 = m_fTexCoords[c-32][0];
  387.         FLOAT ty1 = m_fTexCoords[c-32][1];
  388.         FLOAT tx2 = m_fTexCoords[c-32][2];
  389.         FLOAT ty2 = m_fTexCoords[c-32][3];
  390.  
  391.         FLOAT w = (tx2-tx1) * m_dwTexWidth  / m_fTextScale;
  392.         FLOAT h = (ty2-ty1) * m_dwTexHeight / m_fTextScale;
  393.  
  394.         *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+h-0.5f,0.5f,2.0f), dwColor, tx1, ty2 );
  395.         *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+h-0.5f,0.5f,2.0f), dwColor, tx2, ty2 );
  396.         *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+0-0.5f,sy+0-0.5f,0.5f,2.0f), dwColor, tx1, ty1 );
  397.         *pVertices++ = InitFont2DVertex( D3DXVECTOR4(sx+w-0.5f,sy+0-0.5f,0.5f,2.0f), dwColor, tx2, ty1 );
  398.  
  399.         dwNumTriangles += 2;
  400.  
  401.         m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
  402.                                     D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1,
  403.                                     &m_VB[0], dwNumTriangles*2, D3DDP_WAIT);
  404.         pVertices = &m_VB[0];
  405.         dwNumTriangles = 0L;
  406.  
  407.         sx += w;
  408.     }
  409.     return S_OK;
  410. }
  411.  
  412.